home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
MiscKit1.7.1
/
MiscKit
/
Source
/
MiscGISKit
/
MiscIrelandCoordConverter.m
< prev
next >
Wrap
Text File
|
1995-07-20
|
9KB
|
269 lines
/*====================== MiscIrelandCoordConverter.m ========================*/
/* MiscIrelandCoordConverter class supports the calculations required for
converting between World and the Irish version of the Universal Transverse
Mercator coordinates.
There is only one instance ever, so unless changes are made, this class
is NON REENTRANT.
For information on the underlying mathematics, refer to:
1- Ordinance Survey Information, "Transverse Mercator Projection,
Constants, Formula and Methods", March 1983
2- Ordinance Survey, "Tables for the Transverse Mercator Projection
of Ireland", 1953, reprinted 1971
NOTES:
- Irish document uses old tables and some constants to keep
values small. This has no effect here.
- UK document has IIIA and XIIA equation, ie extra correction terms,
which are not used on Irish Grid and are left out here.
- UK document cancels the -'s in V and VI and the -'s in the E
equation, which the Irish Grid does not do. This has no effect.
- Irish document last term in VI is an extra one not present in UK
but is included here.
- There is an erratum to the Irish document that gives the new
values of a and b. Old values are in the IrishGridOldUTMConstants,
new ones are in the IrishGridUTMConstants object.
- Accuracy is difficult to compare with the example values in the
document because they are derived from tables with interpolation.
Our calculated values are within .1 meter of the one from the
table, and it is probably due to the fact that the tabular examples
do not use "second differences". In other words, the calculated
values are probably more correct to more places than the book
example values.
IMPORTANT: These equations are accurate to within 1 millimeter. Calculations
requiring greater accuracy must use formulae in:
Redfern, JCB, "Transverse Mercator Formulae", 1948,
Empire Survey Review, 9(69) pg318-322
Extra decimal places are stored only for the purpose of
slowing error propagation that affects the numbers at the
millimeter scale, not because they are meaningful in and of
themselves.
DMA Release 0.8, Copyright @1993 by Genesis Project, Ltd. All Rights
Reserved. For further information on terms and conditions see:
Documentation/GISKit/Agreements-Legal-README
HISTORY
12-Mar-93 Dale Amon at GPL
Split UTMGrid into constants and convertor parts.
22-Feb-93 Dale Amon at GPL
Created.
*/
#import <math.h>
#import <misckit/miscgiskit.h>
@implementation MiscIrelandCoordConverter
/*---------------------------------------------------------------------------*/
/* Calculate latitude and longitude given grid N and E. Accurate to 1 mm.
Uses constants:
lambda0 = longitude of grid origin
*/
- (void) utmToWorld
{ double E,N;
double phiPrime;
double y,y2,y3,y4,y5,y6;
double nu2,nu3,nu4,nu5,nu7;
double tanPhiPrime,tan2PhiPrime,tan4PhiPrime,tan6PhiPrime;
double secPhiPrime;
double VII, VIII,IX, X, XI, XII;
/* conversion is driven by the source constants */
xlate = srcConstants;
E = src[MISC_EASTINGS];
N = src[MISC_NORTHINGS];
phiPrime = [self calcPhiPrime: N];
/* precalculate nu, rho and etaSqrd and powers of nu */
[self blackboardCalc: phiPrime];
nu2 = nu*nu;
nu3 = nu2*nu;
nu4 = nu2*nu2;
nu5 = nu3*nu2;
nu7 = nu4*nu3;
/* precalculate all the trig values */
tanPhiPrime = tan(phiPrime);
tan2PhiPrime = tanPhiPrime * tanPhiPrime;
tan4PhiPrime = tan2PhiPrime * tan2PhiPrime;
tan6PhiPrime = tan4PhiPrime * tan2PhiPrime;
secPhiPrime = 1/cos(phiPrime);
/* precalculate all the powers of delta E */
y = E - xlate->E0;
y2 = y*y;
y3 = y2*y;
y4 = y2*y2;
y5 = y3*y2;
y6 = y3*y3;
/* Calculate the terms used by the latitude and longitude equations */
VII = tanPhiPrime/(2.0*rho*nu);
VIII = tanPhiPrime/(24.0*rho*nu3) *
(5.0 + 3.0*tan2PhiPrime + etaSqrd - 9.0*etaSqrd*tan2PhiPrime);
IX = tanPhiPrime/(720.0*rho*nu5) *
(61.0 + 90.0*tan2PhiPrime + 45.0*tan4PhiPrime);
X = secPhiPrime/nu;
XI = secPhiPrime/(6.0*nu3) * (nu/rho + 2.0*tan2PhiPrime);
XII = secPhiPrime/(120.0*nu5) *
(5.0 + 28.0*tan2PhiPrime + 24.0*tan4PhiPrime);
/* and finally, we give you the latitude and the longitude */
dst[MISC_LATITUDE] = phiPrime - y2*VII + y4*VIII + y6*IX;
dst[MISC_LONGITUDE] = xlate->lambda0 + y*X - y3*XI + y5*XII;
dst[MISC_ALTITUDE] = src[MISC_ELEVATION];
}
/*---------------------------------------------------------------------------*/
/* Given World Coordinates, calculate the local grid coordinates in
a UTM projection.
Uses constants:
N0,E0 = True origin offset from grid False origin
lambda0 = longitude of True origin.
*/
- (void) worldToUTM
{ double phi,lambda;
double cosPhi,cos2Phi,cos3Phi,cos5Phi;
double tanPhi,tan2Phi,tan4Phi;
double P1, P2, P3, P4, P5;
double I,II,III,IV,V,VI;
/* conversion is driven by the destination constants */
xlate = dstConstants;
/* assumes the internal storage format is double precision radians */
phi = src[MISC_LATITUDE]; lambda = src[MISC_LONGITUDE];
/* Calculate the Developed Arc of a Meridian from phi to the
True Origin. */
[self calcM: phi];
/* calculate nu, rho and etaSqrd */
[self blackboardCalc: phi];
/* precalculate all the trig values that are not on blackboard */
cosPhi = cos(phi);
cos2Phi = cosPhi*cosPhi;
cos3Phi = cos2Phi*cosPhi;
cos5Phi = cos2Phi*cos3Phi;
tanPhi = tan(phi);
tan2Phi = tanPhi * tanPhi;
tan4Phi = tan2Phi * tan2Phi;
/* Precalculate all the powers of delta lambda */
P1 = lambda - xlate->lambda0;
P2 = P1 * P1;
P3 = P2 * P1;
P4 = P2 * P2;
P5 = P3 * P2;
/* Calculate the terms used by the Easting and Northing equations */
I = M + xlate->N0;
II = nu/2.0 * sinPhi * cosPhi;
III = nu/24.0 * sinPhi * cos3Phi * (5.0 - tan2Phi + 9.0 * etaSqrd);
IV = nu * cosPhi;
V = nu/6.0 * cos3Phi * (nu/rho - tan2Phi);
/* The Irish equation has one extra term in VI that the UK
and UTM to not have. */
VI = nu/120.0 * cos5Phi *
(5.0 - 18.0*tan2Phi + tan4Phi + 14.0*etaSqrd -
58.0 * etaSqrd * tan2Phi + 2.0 * etaSqrd * tan4Phi);
/* And finally, we calculate the local grid coordinates */
dst[MISC_NORTHINGS] = I + P2*II + P4*III;
dst[MISC_EASTINGS] = xlate->E0 + P1*IV + P3*V + P5*VI;
dst[MISC_ELEVATION] = src[MISC_ALTITUDE];
}
/*===========================================================================*/
/* Class methods */
/*===========================================================================*/
/* Only one converter of this type is every needed. Of course if we got
into a really big multiprocess agora system there might be a case
for multiple converters. Since this object is shared by many, it
doesn't particularly matter what zone it is allocated from.
Note that we use a secret allocation routine. The parent class blocks the
normal alloc's because it also creates only a single instance.
*/
static id theIrelandCoordConverter = nil;
+ new
{
if (!theIrelandCoordConverter)
theIrelandCoordConverter = [[super superalloc] init];
return theIrelandCoordConverter;
}
/*===========================================================================*/
/* Initialization methods */
/*===========================================================================*/
/* We add a list of all the services which we are able to provide.
Note that there is only one MiscIrelandCoordConverter ever created. Once
initialized the same object is given to all comers and can not be destroyed.
Simple copies when the class is the same is okay because we know that
by definition the UTM constants are be the same.
*/
- init
{ Class world, utm, oldutm;
[super init];
world = [MiscWorldCoord class];
utm = [MiscIrelandUTMCoord class];
oldutm = [MiscIrelandOldUTMCoord class];
[self addService: @selector(utmToWorld) convertsFrom: utm to: world];
[self addService: @selector(worldToUTM) convertsFrom: world to: utm];
[self addService: @selector(utmToWorld) convertsFrom: oldutm to: world];
[self addService: @selector(worldToUTM) convertsFrom: world to: oldutm];
[self addService: @selector(copyCoords) convertsFrom: world to: world];
[self addService:[self fastCopySelector] convertsFrom: utm to: utm];
[self addService:[self fastCopySelector] convertsFrom:oldutm to: oldutm];
return self;
}
/*===========================================================================*/
/* Archive methods */
/*===========================================================================*/
- finishUnarchiving
{
[self free];
return [MiscIrelandCoordConverter new];
}
@end